package com.strugglerz.web.base.utils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * 提供加密解密常用函数
 * 
 * add by hkNaruto 2012-02-23
 */
@SuppressWarnings("static-access")
public class EncryptTool {

    /** logger */
    private static final Logger logger = LoggerFactory.getLogger(EncryptTool.class);

    /** 响应加密用 */
    private static SecretKey secretKey = null;

    /** 是否已经初始化密钥 */
    private static AtomicBoolean keyIniting = new AtomicBoolean(false);

    /** 密钥文件 */
    private static final String KEY_PATH = "/deskey.data";

    static {
        /**
         * 添加加密算法，所有客户端响应均加密传输 2013-05-08
         */
        if (!keyIniting.get()) {
            keyIniting.set(true);
            try {
                secretKey = EncryptTool.getDESKeyFromFile(EncryptTool.class.getResource(KEY_PATH).getPath());
            } catch (Exception e) {
                keyIniting.set(false);
                throw new RuntimeException("EncryptTool secretKey init failure !!!", e);
            }
        }

        if (!keyIniting.get()) {
            keyIniting.set(false);
            throw new RuntimeException("EncryptTool secretKey init failure !!!");
        }
    }

    /**
     * 结果对象加密结果
     * 
     * @param resultMap
     * @return
     */
    public static String getEncryptResult(String originMessage) {

        if (secretKey == null) {
            logger.error("message encrypt failure,originMessage = {}", originMessage);
            return null;
        }

        return EncryptTool.DESEncrypt(originMessage, secretKey);
    }

    /*
     * md5加密函数
     * @param input 输入字符串
     * @return MD5字符串大写 add by hkNaruto 2012-02-23
     */
    public static String getMD5String(String input) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(input.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            // System.out.println("NoSuchAlgorithmException caught!");
            // System.exit(-1);
            logger.error(e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        }

        byte[] byteArray = messageDigest.digest();
        StringBuffer md5StrBuff = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
                md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
            else
                md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
        }
        return md5StrBuff.toString().toUpperCase();
    }

    public static String DESEncrypt(String input, SecretKey key) {
        byte[] bytes = null;
        try {
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(cipher.ENCRYPT_MODE, key);
            bytes = cipher.doFinal(input.getBytes());
            return SerializeTool.byteArrayToHexString(bytes);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 加密二进制
     * 
     * @param input
     * @param key
     * @return
     */
    public static String DESEncrypt(byte[] input, SecretKey key) {
        byte[] bytes = null;
        try {
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(cipher.ENCRYPT_MODE, key);
            bytes = cipher.doFinal(input);
            return SerializeTool.byteArrayToHexString(bytes);
        } catch (Exception e) {

        }
        return null;
    }

    public static String DESDecrypt(String input, SecretKey key) {
        byte[] bytes = null;
        try {
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(cipher.DECRYPT_MODE, key);
            bytes = cipher.doFinal(SerializeTool.hexStringToByteArray(input));
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密二进制
     * 
     * @param enc
     * @param key
     * @return
     */
    public static String DESDecrypt(byte[] enc, SecretKey key) {
        byte[] bytes = null;
        try {
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(cipher.DECRYPT_MODE, key);
            bytes = cipher.doFinal(enc);
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SecretKey createDESSecretKey() {
        try {
            return KeyGenerator.getInstance("DES").generateKey();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    public static void saveKeyFile(SecretKey key, String fileFullPath) throws Exception {
        FileOutputStream fileOutputStream = new FileOutputStream(fileFullPath);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(key);
        objectOutputStream.close();
        fileOutputStream.close();
    }

    public static SecretKey getDESKeyFromFile(String fileFullPath) {
        try {
            FileInputStream fileInputStream = new FileInputStream(fileFullPath);
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            SecretKey secretKey = (SecretKey) objectInputStream.readObject();
            fileInputStream.close();
            return secretKey;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    public static SecretKey getDESKeyFromStream(InputStream stream) {
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(stream);
            return (SecretKey) objectInputStream.readObject();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    public static SecretKey getDESKeyFromString(String key) {
        try {
            DESKeySpec spec = new DESKeySpec(key.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(spec);
            return secretKey;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
